// Copyright Epic Games, Inc. All Rights Reserved.

#include "CommonInputBaseTypes.h"
#include "EnhancedInputSubsystems.h"
#include "CustomSettings/LyraSettingKeyboardInput.h"
#include "DataSource/GameSettingDataSource.h"
#include "EditCondition/WhenCondition.h"
#include "GameSettingCollection.h"
#include "GameSettingValueDiscreteDynamic.h"
#include "GameSettingValueScalarDynamic.h"
#include "LyraGameSettingRegistry.h"
#include "LyraSettingsLocal.h"
#include "LyraSettingsShared.h"
#include "Player/LyraLocalPlayer.h"
#include "PlayerMappableInputConfig.h"

class ULocalPlayer;

#define LOCTEXT_NAMESPACE "Lyra"

/**
 * 初始化鼠标和键盘设置
 * @param InLocalPlayer 本地玩家
 * @return 游戏设置集合
 */
UGameSettingCollection* ULyraGameSettingRegistry::InitializeMouseAndKeyboardSettings(ULyraLocalPlayer* InLocalPlayer)
{
	UGameSettingCollection* Screen = NewObject<UGameSettingCollection>(); // 创建游戏设置集合
	Screen->SetDevName(TEXT("MouseAndKeyboardCollection")); // 设置开发名称
	Screen->SetDisplayName(LOCTEXT("MouseAndKeyboardCollection_Name", "Mouse & Keyboard")); // 设置显示名称
	Screen->Initialize(InLocalPlayer); // 初始化

	const TSharedRef<FWhenCondition> WhenPlatformSupportsMouseAndKeyboard = MakeShared<FWhenCondition>( // 创建平台支持鼠标和键盘的条件
		[](const ULocalPlayer*, FGameSettingEditableState& InOutEditState)
		{
			const UCommonInputPlatformSettings* PlatformInput = UPlatformSettingsManager::Get().GetSettingsForPlatform<UCommonInputPlatformSettings>(); // 获取平台输入设置
			if (!PlatformInput->SupportsInputType(ECommonInputType::MouseAndKeyboard)) // 如果平台不支持鼠标和键盘输入类型
			{
				InOutEditState.Kill(TEXT("Platform does not support mouse and keyboard")); // 禁用设置
			}
		});

	// 鼠标灵敏度
	////////////////////////////////////////////////////////////////////////////////////
	{
		UGameSettingCollection* Sensitivity = NewObject<UGameSettingCollection>(); // 创建灵敏度设置集合
		Sensitivity->SetDevName(TEXT("MouseSensitivityCollection")); // 设置开发名称
		Sensitivity->SetDisplayName(LOCTEXT("MouseSensitivityCollection_Name", "Sensitivity")); // 设置显示名称
		Screen->AddSetting(Sensitivity); // 添加到屏幕设置

		//----------------------------------------------------------------------------------
		{
			UGameSettingValueScalarDynamic* Setting = NewObject<UGameSettingValueScalarDynamic>(); // 创建标量动态值设置
			Setting->SetDevName(TEXT("MouseSensitivityYaw")); // 设置开发名称
			Setting->SetDisplayName(LOCTEXT("MouseSensitivityYaw_Name", "X-Axis Sensitivity")); // 设置显示名称
			Setting->SetDescriptionRichText(LOCTEXT("MouseSensitivityYaw_Description", "Sets the sensitivity of the mouse's horizontal (x) axis. With higher settings the camera will move faster when looking left and right with the mouse.")); // 设置描述富文本

			Setting->SetDynamicGetter(GET_SHARED_SETTINGS_FUNCTION_PATH(GetMouseSensitivityX)); // 设置动态获取器
			Setting->SetDynamicSetter(GET_SHARED_SETTINGS_FUNCTION_PATH(SetMouseSensitivityX)); // 设置动态设置器
			Setting->SetDefaultValue(GetDefault<ULyraSettingsShared>()->GetMouseSensitivityX()); // 设置默认值
			Setting->SetDisplayFormat(UGameSettingValueScalarDynamic::RawTwoDecimals); // 设置显示格式
			Setting->SetSourceRangeAndStep(TRange<double>(0, 10), 0.01); // 设置源范围和步长
			Setting->SetMinimumLimit(0.01); // 设置最小限制

			Setting->AddEditCondition(WhenPlatformSupportsMouseAndKeyboard); // 添加编辑条件

			Sensitivity->AddSetting(Setting); // 添加到灵敏度设置
		}
		//----------------------------------------------------------------------------------
		{
			UGameSettingValueScalarDynamic* Setting = NewObject<UGameSettingValueScalarDynamic>(); // 创建标量动态值设置
			Setting->SetDevName(TEXT("MouseSensitivityPitch")); // 设置开发名称
			Setting->SetDisplayName(LOCTEXT("MouseSensitivityPitch_Name", "Y-Axis Sensitivity")); // 设置显示名称
			Setting->SetDescriptionRichText(LOCTEXT("MouseSensitivityPitch_Description", "Sets the sensitivity of the mouse's vertical (y) axis. With higher settings the camera will move faster when looking up and down with the mouse.")); // 设置描述富文本

			Setting->SetDynamicGetter(GET_SHARED_SETTINGS_FUNCTION_PATH(GetMouseSensitivityY)); // 设置动态获取器
			Setting->SetDynamicSetter(GET_SHARED_SETTINGS_FUNCTION_PATH(SetMouseSensitivityY)); // 设置动态设置器
			Setting->SetDefaultValue(GetDefault<ULyraSettingsShared>()->GetMouseSensitivityY()); // 设置默认值
			Setting->SetDisplayFormat(UGameSettingValueScalarDynamic::RawTwoDecimals); // 设置显示格式
			Setting->SetSourceRangeAndStep(TRange<double>(0, 10), 0.01); // 设置源范围和步长
			Setting->SetMinimumLimit(0.01); // 设置最小限制

			Setting->AddEditCondition(WhenPlatformSupportsMouseAndKeyboard); // 添加编辑条件

			Sensitivity->AddSetting(Setting); // 添加到灵敏度设置
		}
		//----------------------------------------------------------------------------------
		{
			UGameSettingValueScalarDynamic* Setting = NewObject<UGameSettingValueScalarDynamic>(); // 创建标量动态值设置
			Setting->SetDevName(TEXT("MouseTargetingMultiplier")); // 设置开发名称
			Setting->SetDisplayName(LOCTEXT("MouseTargetingMultiplier_Name", "Targeting Sensitivity")); // 设置显示名称
			Setting->SetDescriptionRichText(LOCTEXT("MouseTargetingMultiplier_Description", "Sets the modifier for reducing mouse sensitivity when targeting. 100% will have no slow down when targeting. Lower settings will have more slow down when targeting.")); // 设置描述富文本

			Setting->SetDynamicGetter(GET_SHARED_SETTINGS_FUNCTION_PATH(GetTargetingMultiplier)); // 设置动态获取器
			Setting->SetDynamicSetter(GET_SHARED_SETTINGS_FUNCTION_PATH(SetTargetingMultiplier)); // 设置动态设置器
			Setting->SetDefaultValue(GetDefault<ULyraSettingsShared>()->GetTargetingMultiplier()); // 设置默认值
			Setting->SetDisplayFormat(UGameSettingValueScalarDynamic::RawTwoDecimals); // 设置显示格式
			Setting->SetSourceRangeAndStep(TRange<double>(0, 10), 0.01); // 设置源范围和步长
			Setting->SetMinimumLimit(0.01); // 设置最小限制

			Setting->AddEditCondition(WhenPlatformSupportsMouseAndKeyboard); // 添加编辑条件

			Sensitivity->AddSetting(Setting); // 添加到灵敏度设置
		}
		//----------------------------------------------------------------------------------
		{
			UGameSettingValueDiscreteDynamic_Bool* Setting = NewObject<UGameSettingValueDiscreteDynamic_Bool>(); // 创建布尔离散值设置
			Setting->SetDevName(TEXT("InvertVerticalAxis")); // 设置开发名称
			Setting->SetDisplayName(LOCTEXT("InvertVerticalAxis_Name", "Invert Vertical Axis")); // 设置显示名称
			Setting->SetDescriptionRichText(LOCTEXT("InvertVerticalAxis_Description", "Enable the inversion of the vertical look axis.")); // 设置描述富文本

			Setting->SetDynamicGetter(GET_SHARED_SETTINGS_FUNCTION_PATH(GetInvertVerticalAxis)); // 设置动态获取器
			Setting->SetDynamicSetter(GET_SHARED_SETTINGS_FUNCTION_PATH(SetInvertVerticalAxis)); // 设置动态设置器
			Setting->SetDefaultValue(GetDefault<ULyraSettingsShared>()->GetInvertVerticalAxis()); // 设置默认值

			Setting->AddEditCondition(WhenPlatformSupportsMouseAndKeyboard); // 添加编辑条件

			Sensitivity->AddSetting(Setting); // 添加到灵敏度设置
		}
		//----------------------------------------------------------------------------------
		{
			UGameSettingValueDiscreteDynamic_Bool* Setting = NewObject<UGameSettingValueDiscreteDynamic_Bool>(); // 创建布尔离散值设置
			Setting->SetDevName(TEXT("InvertHorizontalAxis")); // 设置开发名称
			Setting->SetDisplayName(LOCTEXT("InvertHorizontalAxis_Name", "Invert Horizontal Axis")); // 设置显示名称
			Setting->SetDescriptionRichText(LOCTEXT("InvertHorizontalAxis_Description", "Enable the inversion of the Horizontal look axis.")); // 设置描述富文本

			Setting->SetDynamicGetter(GET_SHARED_SETTINGS_FUNCTION_PATH(GetInvertHorizontalAxis)); // 设置动态获取器
			Setting->SetDynamicSetter(GET_SHARED_SETTINGS_FUNCTION_PATH(SetInvertHorizontalAxis)); // 设置动态设置器
			Setting->SetDefaultValue(GetDefault<ULyraSettingsShared>()->GetInvertHorizontalAxis()); // 设置默认值

			Setting->AddEditCondition(WhenPlatformSupportsMouseAndKeyboard); // 添加编辑条件

			Sensitivity->AddSetting(Setting); // 添加到灵敏度设置
		}
		//----------------------------------------------------------------------------------
	}

	// 鼠标和键盘的键位绑定 - 自动生成
	////////////////////////////////////////////////////////////////////////////////////
	{
		UGameSettingCollection* KeyBinding = NewObject<UGameSettingCollection>(); // 创建键位绑定设置集合
		KeyBinding->SetDevName(TEXT("KeyBindingCollection")); // 设置开发名称
		KeyBinding->SetDisplayName(LOCTEXT("KeyBindingCollection_Name", "Keyboard & Mouse")); // 设置显示名称
		Screen->AddSetting(KeyBinding); // 添加到屏幕设置

		const UEnhancedInputLocalPlayerSubsystem* EISubsystem = InLocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(); // 获取增强输入本地玩家子系统
		const UEnhancedInputUserSettings* UserSettings = EISubsystem->GetUserSettings(); // 获取用户设置

		// 如果您只想获取一个配置文件对，可以使用 UserSettings->GetCurrentProfile

		// 键位绑定到其显示类别的映射
		TMap<FString, UGameSettingCollection*> CategoryToSettingCollection; // 类别到设置集合的映射

		// 返回显示类别的现有设置集合（如果有）
		// 如果没有，则创建新的并初始化
		auto GetOrCreateSettingCollection = [&CategoryToSettingCollection, &Screen](FText DisplayCategory) -> UGameSettingCollection* // 获取或创建设置集合的Lambda函数
		{
			static const FString DefaultDevName = TEXT("Default_KBM"); // 默认开发名称
			static const FText DefaultDevDisplayName = NSLOCTEXT("LyraInputSettings", "LyraInputDefaults", "Default Experiences"); // 默认显示名称

			if (DisplayCategory.IsEmpty()) // 如果显示类别为空
			{
				DisplayCategory = DefaultDevDisplayName; // 使用默认显示类别
			}
			
			FString DisplayCatString = DisplayCategory.ToString(); // 转换为字符串
			
			if (UGameSettingCollection** ExistingCategory = CategoryToSettingCollection.Find(DisplayCatString)) // 如果找到现有类别
			{
				return *ExistingCategory; // 返回现有类别
			}
			
			UGameSettingCollection* ConfigSettingCollection = NewObject<UGameSettingCollection>(); // 创建配置设置集合
			ConfigSettingCollection->SetDevName(FName(DisplayCatString)); // 设置开发名称
			ConfigSettingCollection->SetDisplayName(DisplayCategory); // 设置显示名称
			Screen->AddSetting(ConfigSettingCollection); // 添加到屏幕设置
			CategoryToSettingCollection.Add(DisplayCatString, ConfigSettingCollection); // 添加到映射
			
			return ConfigSettingCollection; // 返回配置设置集合
		};

		static TSet<FName> CreatedMappingNames; // 已创建的映射名称集合
		CreatedMappingNames.Reset(); // 重置已创建的映射名称
		
		for (const TPair<FString, TObjectPtr<UEnhancedPlayerMappableKeyProfile>>& ProfilePair : UserSettings->GetAllAvailableKeyProfiles()) // 遍历所有可用的键配置文件
		{
			const FString& ProfileName = ProfilePair.Key; // 配置文件名称
			const TObjectPtr<UEnhancedPlayerMappableKeyProfile>& Profile = ProfilePair.Value; // 配置文件

			for (const TPair<FName, FKeyMappingRow>& RowPair : Profile->GetPlayerMappingRows()) // 遍历玩家映射行
			{
				// 为任何具有有效映射且尚未创建的内容创建设置行
				if (RowPair.Value.HasAnyMappings() /* && !CreatedMappingNames.Contains(RowPair.Key)*/) // 如果有任何映射且尚未创建
				{
					// 我们只希望在此设置屏幕上显示键盘键，因此我们将按映射过滤设置为键盘键
					FPlayerMappableKeyQueryOptions Options = {}; // 玩家可映射键查询选项
					Options.KeyToMatch = EKeys::W; // 匹配的键
					Options.bMatchBasicKeyTypes = true; // 匹配基本键类型
															
					const FText& DesiredDisplayCategory = RowPair.Value.Mappings.begin()->GetDisplayCategory(); // 期望的显示类别
					
					if (UGameSettingCollection* Collection = GetOrCreateSettingCollection(DesiredDisplayCategory)) // 获取或创建设置集合
					{
						// 创建设置小部件并初始化，将其添加到此配置的部分中
						ULyraSettingKeyboardInput* InputBinding = NewObject<ULyraSettingKeyboardInput>(); // 创建键盘输入设置

						InputBinding->InitializeInputData(Profile, RowPair.Value, Options); // 初始化输入数据
						InputBinding->AddEditCondition(WhenPlatformSupportsMouseAndKeyboard); // 添加编辑条件

						Collection->AddSetting(InputBinding); // 添加到集合
						CreatedMappingNames.Add(RowPair.Key); // 添加到已创建的映射名称
					}
					else
					{
						ensure(false); // 确保不会发生
					}
				}
			}
		}
	}

	return Screen; // 返回屏幕设置集合
}

#undef LOCTEXT_NAMESPACE